package com.lry.pda.bottom.c.backend.code;

import com.lry.pda.bottom.c.backend.type.Symbol;
import com.lry.pda.bottom.c.backend.type.TypeSystem;
import com.lry.pda.bottom.c.frontend.CTokenType;
import com.lry.pda.bottom.c.frontend.Grammar;
import com.lry.pda.bottom.c.frontend.LRValueParser;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class CodeTreeBuilder {

    private Stack<CodeNode> codeNodeStack = new Stack<>();
    private LRValueParser parser;
    private TypeSystem typeSystem = TypeSystem.getSelf();
    private Stack<Object> valueStack;
    private String funcName;
    public Map<String,CodeNode> funcMap = new HashMap<>();

    private static CodeTreeBuilder treeBuilder = null;
    public static CodeTreeBuilder getSelf(){
        if (treeBuilder == null) {
            treeBuilder = new CodeTreeBuilder();
        }

        return treeBuilder;
    }

    public void clear(){
        this.codeNodeStack.clear();
    }
    public void setParser(LRValueParser parser){
        this.parser = parser;
        this.valueStack = parser.valueStack;
    }


    public void buildCodeTree(int production,String text){
        CodeNode node = null;
        Symbol symbol = null;
        CodeNode child = null;

        if(production== Grammar.Number_TO_Unary
            ||production==Grammar.String_TO_Unary
                ||production==Grammar.FALSE_TO_Unary
                ||production==Grammar.TRUE_TO_Unary
        ){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.setAttr(CodeKey.TEXT,text);
        }
        else if(production==Grammar.Name_TO_Unary){
            node = new CodeNodeImpl(CTokenType.UNARY);
            symbol = typeSystem.getSymbolByText(text,parser.nestingLevel,parser.scope);
            node.setAttr(CodeKey.SYMBOL,symbol);
            node.setAttr(CodeKey.TEXT,text);
        }
        else if(production==Grammar.Unary_LB_Expr_RB_TO_Unary){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.addChild(codeNodeStack.pop());//EXPR
            node.addChild(codeNodeStack.pop());//UNARY
        }else if(production==Grammar.UNARY_INCOP_TO_UNARY
            ||production==Grammar.UNARY_DECOP_TO_UNARY
        ||production==Grammar.INCOP_UNARY_TO_UNARY
        ||production==Grammar.DECOP_UNARY_TO_UNARY
        ||production==Grammar.MINUS_UNARY_TO_UNARY
        ||production==Grammar.STAR_UNARY_TO_UNARY
        ||production==Grammar.LP_EXPR_RP_TO_UNARY){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Unary_TO_Binary){
            node = new CodeNodeImpl(CTokenType.BINARY);
            child = codeNodeStack.pop();
            node.setAttr(CodeKey.TEXT,child.getAttr(CodeKey.TEXT));
            node.addChild(child);
        }
        else if(production==Grammar.Binary_TO_NoCommaExpr){
            node = new CodeNodeImpl(CTokenType.NO_COMMA_EXPR);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.NoCommaExpr_Equal_NoCommaExpr_TO_NoCommaExpr){
            node = new CodeNodeImpl(CTokenType.NO_COMMA_EXPR);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Binary_Plus_Binary_TO_Binary
        ||production==Grammar.Binary_Minus_Binary_TO_Binary
        ||production==Grammar.Binary_Star_Binary_TO_Binary
        ||production==Grammar.Binary_Divop_Binary_TO_Binary
        ||production==Grammar.Binary_LShiftOp_Binary_TO_Binary
        ||production==Grammar.Binary_RShiftOp_Binary_TO_Binary
        ||production==Grammar.Binary_And_Binary_TO_Binary
        ||production==Grammar.Binary_OR_Binary_TO_Binary
        ||production==Grammar.Binary_XOR_Binary_TO_Binary
        ||production==Grammar.Binary_Mod_Binary_TO_Binary
                ||production==Grammar.BINARY_OROR_BINARY_TO_BINARY
                ||production==Grammar.BINARY_ANDAND_BINARY_TO_BINARY
        ){
            node = new CodeNodeImpl(CTokenType.BINARY);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.NOT_BINARY_TO_BINARY){
            node = new CodeNodeImpl(CTokenType.BINARY);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Binary_RelOP_Binary_TO_Binary){
            node = new CodeNodeImpl(CTokenType.BINARY);
            node.addChild(codeNodeStack.pop());

            CodeNode operator = new CodeNodeImpl(CTokenType.RELOP);
            operator.setAttr(CodeKey.TEXT, parser.relOperatorText);
            node.addChild(operator);

            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.UNARY_COMPOUND_ASSIGN_UNARY_TO_UNARY){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.addChild(codeNodeStack.pop());

            CodeNode operator = new CodeNodeImpl(CTokenType.COMPOUND_ASSIGN);
            operator.setAttr(CodeKey.TEXT, parser.compoundAssignText);
            node.addChild(operator);

            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.NoCommaExpr_TO_Expr){
            node = new CodeNodeImpl(CTokenType.EXPR);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Expr_Semi_TO_Statement){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.LocalDefs_TO_Statement){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Statement_TO_StmtList){
            node = new CodeNodeImpl(CTokenType.STMT_LIST);
            if (codeNodeStack.size() > 0) {
                node.addChild(codeNodeStack.pop());
            }
        }
        else if(production==Grammar.StmtList_Statement_TO_StmtList){
            node = new CodeNodeImpl(CTokenType.STMT_LIST);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.Expr_TO_Test){
            node = new CodeNodeImpl(CTokenType.TEST);
            node.addChild(codeNodeStack.pop());
        }
        else if(production==Grammar.If_Test_Statement_TO_IFStatement){
            node = new CodeNodeImpl(CTokenType.IF_STATEMENT);
            node.addChild(codeNodeStack.pop()); //Test
            node.addChild(codeNodeStack.pop()); //Statement
        }
        else if(production==Grammar.IfElseStatement_Else_Statement_TO_IfElseStatement){
            node = new CodeNodeImpl(CTokenType.IF_ELSE_STATEMENT);
            node.addChild(codeNodeStack.pop()); //IfStatement
            node.addChild(codeNodeStack.pop()); //Statement
        }else if(production==Grammar.Var_Decl_Init_To_Decl){
            node = new CodeNodeImpl(CTokenType.DECL);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.NewName_TO_VarDecl) {
            //我们暂时不处理变量声明语句
//            codeNodeStack.pop();
        }else if(production==Grammar.NAME_TO_NewName) {
            node = new CodeNodeImpl(CTokenType.NEW_NAME);
            node.setAttr(CodeKey.SCOPE,parser.scope);
            node.setAttr(CodeKey.TEXT, text);
            node.setAttr(CodeKey.LEVEL, parser.nestingLevel);
        }else if(production==Grammar.SPECIFIERS_DECL_LIST_TO_DEF){
            System.out.println(1);
        }else if(production==Grammar.DECL_LIST_COMMA_DECL_TO_DECL_LIST){
            node = new CodeNodeImpl(CTokenType.DECL_LIST);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.DECL_TO_DECL_LIST){
            node = new CodeNodeImpl(CTokenType.DECL_LIST);
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.FOR_OPTEXPR_TEST_ENDOPTEXPR_STAT_TO_STAT){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());//OPTEXPR
            node.addChild(codeNodeStack.pop());//TEST
            node.addChild(codeNodeStack.pop());//ENDOPTEXPR
            node.addChild(codeNodeStack.pop());//STAT
        }else if(production==Grammar.EXPR_SEMI_TO_OPTEXPR){
            node = new CodeNodeImpl(CTokenType.OPT_EXPR);
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.SEMI_TO_OPTEXPR){
            node = new CodeNodeImpl(CTokenType.OPT_EXPR);
        }else if(production==Grammar.EXPR_TO_ENDOPTEXPR){
            node = new CodeNodeImpl(CTokenType.END_OPT_EXPR);
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.WHILE_TEST_STAT_TO_STAT){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());//test
            node.addChild(codeNodeStack.pop());//stat
        }else if(production==Grammar.DO_STAT_WHILE_TEST_TO_STAT){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());//stat
            node.addChild(codeNodeStack.pop());//test
        }
        //函数体实现 type func(){com_stat}
        else if(production==Grammar.OPT_SPECIFIERS_FUNCT_DECL_COMPOUND_STMT_TO_EXT_DEF){
            node = new CodeNodeImpl(CTokenType.EXT_DEF);
            node.addChild(codeNodeStack.pop());//FUNCT_DECL
            if(!codeNodeStack.isEmpty()){
                node.addChild(codeNodeStack.pop());//COMPOUND_STMT
            }
            funcMap.put(funcName,node);
        }
        else if(production==Grammar.TYPE_NT_VAR_DECL_TO_PARAM_DECLARATION){
            //忽略函数参数定义
            codeNodeStack.pop();
        }
        //函数定义func()
        else if(production==Grammar.NEW_NAME_LP_RP_TO_FUNCT_DECL||
        production==Grammar.NEW_NAME_LP_VAR_LIST_RP_TO_FUNCT_DECL){
            node = new CodeNodeImpl(CTokenType.FUNCT_DECL);
            node.addChild(codeNodeStack.pop());//NEW_NAME
            child = node.getChildren().get(0);
            funcName = (String) child.getAttr(CodeKey.TEXT);
            assignSymbolToNode(node,funcName);
        }
        //调用无参函数func()
        else if(production==Grammar.UNARY_LP_RP_TO_UNARY){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.addChild(codeNodeStack.pop());
        }
        //调用有参函数
        else if(production==Grammar.UNARY_LP_ARGS_RP_TO_UNARY){
            node = new CodeNodeImpl(CTokenType.UNARY);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        } else if(production==Grammar.NO_COMMA_EXPR_TO_ARGS){
            node = new CodeNodeImpl(CTokenType.ARGS);
            node.addChild(codeNodeStack.pop());
        } else if(production==Grammar.NO_COMMA_EXPR_COMMA_ARGS_TO_ARGS){
            node = new CodeNodeImpl(CTokenType.ARGS);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
        }else if(production==Grammar.RETURN_SEMI_TO_STAT){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
        }else if(production==Grammar.RETURN_EXPR_SEMI_TO_STAT){
            node = new CodeNodeImpl(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());//expr
        }

        if(null!=node){
            node.setAttr((CodeKey.PRODUCTION),production);
            codeNodeStack.push(node);
        }
    }

    private Symbol assignSymbolToNode(CodeNode node, String text) {
        Symbol symbol = typeSystem.getSymbolByText(text, parser.nestingLevel, parser.scope);
        node.setAttr(CodeKey.SYMBOL, symbol);
        node.setAttr(CodeKey.TEXT, text);
        return symbol;
    }

    public CodeNode getTreeRoot(){
        return codeNodeStack.pop();
    }

}


